home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The PC-SIG Library 10
/
The PC-Sig Library - Shareware for the IBM PC and Compatibles (PC-SIG)(Tenth Edition Disks 1-2804)(1991).iso
/
PC_SIGCD
/
14
/
3
/
DISK1433.ZIP
/
G_INTRO.TXT
< prev
next >
Wrap
Text File
|
1989-01-14
|
31KB
|
818 lines
Introduction
This manual introduces a subset of the powerful graphics
functions which are part of the BASIC programming language as
implimented on Hewlett-Packard Series 200/300 Technical
Computers. This manual introduces these functions and explains
their usage. Also provided are a set of example program which
illustrate some of the features of these functions.
The functions do not in themselves constitute a complete program.
Rather, they are used to suppliment a program where graphical
data is to be presented. These functions are distinct from the
functions provided in the Microsoft v. 5.1 C compiler in that
they scale the screen into units defined by the user. The
programmer need not know what the screen size is in pixels to use
these routines, and, in fact, these routine are designed to make
a program independent of the hardware and screen mode used.
It should be pointed out that, like all graphical
representations, these routines perform best with high resolution
screens. They will function with any screen resolution
available, but line resolution improves as screen resolution
increases. Thus, for best results, one would normally use the
highest resolution screen available.
Why the Hewlett-Packard Workstation BASIC Graphics?
There are three reasons why I chose to impliment this particular
set of graphics primitives. First, I was porting some
applications written in HP workstation BASIC to an IBM PC
compatible computer. Since these programs had extensive
graphical displays and would not be nearly as useful without
them, it was manditory to develop these graphic primitives.
Second, it is a well thought out and utilitarian set of
2-dimensional graphics primitives. It is well suited to
presentation of technical information and quite flexible. The
functions are intuitive and easily incorporated into the original
programs, and much of that has carried over into this library.
And lastly, the graphics primitives provided with Microsoft's
verion 5.1 C compiler are difficult to use. They require the
user to keep track of his scaling and units. Although they can
do quite a bit, that nagging problem of converting from user
units to pixels is left to the user. Add to that the inflexible
labeling demands of the PC text interface (it is not possible to
place labels arbitrarily because the text interface is imbedded
in the graphics modes: you must label in text rows and columns)
and the lack of any ability to rotate the text or change font
size without loading completely new fonts made it obvious that
ignoring most of Microsoft's and the PC's graphics functions
would be the best way to proceed.
Why Use Graphics?
The use of graphics to display information is unsurpassed in
intuitive clarity. Trends and patterns are much more readily
recognized on a graph than in tabular form.
For example, examine the following lexical data and try to
visualize the shape of the data:
X Y
0 0.09
20 0.42
40 0.71
60 0.91
80 0.99
100 0.97
120 0.82
140 0.57
160 0.26
180 -0.09
200 -0.42
220 -0.71
240 -0.91
260 -1.00
280 -0.97
300 -0.82
If this were displayed on a graph, it would be immediately
obvious that this is a sinusoid.
Line Drawing
To draw lines, one can simple draw () or plot () the points. The
following short program illustrates this.
#include <stdio.h>
#include <math.h>
#include "graph.h"
double x;
main ()
{
g_init (EGA_640x350);
for (x = 0; x < 70; ++x)
plot (x, 45 + sin (x/100) + x/10, 1);
}
This program illustrates the most basic program one can write.
The call to g_init () initializes the graphics routines and sets
the screen to graphics mode. This is always the first function
called before attempting to plot anything.
The plot () function does exactly what its name implies. It
draw a line from the last pen position to the current pen
position using the current pen color. In this case, a pen
control parameter is included. The value 1 causes the plotting
program to initially move the pen and then drop the pen. Once
the pen is down, it remains down and the plot is drawn. The
constant 45 is used to center the y-values.
When the plotting program is initialized, the screen default
scaling is in Graphics Display Units (GDU's). GDU's have an
origin in the lower left corner of the CRT and have values from 0
to 100 for the shorter side of the CRT (usually the y-
direction). The value for the longer side of the CRT depends on
the hardware and drawing mode. This can range from 100 to 150 or
higher. In this example, it was assumed that the screen was 100
GDU's tall and 140 GDU's wide. Thus, this program will draw a
sinusoid 2 GDU's tall over 1/2 of the screen.
Scaling A Plot
If you were to execute this program as it is written, the results
would be disappointing. There would be almost nothing to see.
However, if the Y scale is changed, the variations would become
much more visible and would better represent the data.
For this problem, we have scaling functions. These functions
define values which the computer considers to be the edges of the
plotting area. By definition, the left edges is the minimum x-
value and the right edges is the maximum x-value. Similarly, the
bottom edges is the minimum y-value and the top edge represents
the maximum y-value. Any point plotted within these ranges will
be visible. There are three functions which can be used to
define the edges of the plotting area: show (), scale (), and
mscale ().
The first function, show (), is an isotropic scaling function.
This type of scaling is most useful when displaying geometric
data. show () forces the physical representation of the x-units
and y-units to be equal. If the plotting area is square and one
uses
show (0, 100, 10, 30)
to scale that area, the minimum x-value would be zero, the
maximum x-value would be 100, the minimum y-value would be -30,
and the maximum y-value would be 70. The reason for this is that
the x- and y- units are identical. The show () function centers
the specified area in the plotting area and takes whatever extra
room it requires to make the units equal. Depending on the shape
of the plotting area and the scaling values, there will always be
extra room in either the x- or y-direction, but never both.
Once the show () function has been executed, the plotting area is
defined in User-Defined Units (UDU's). If we re-write the
example program,
#include <stdio.h>
#include <math.h>
#include "graph.h"
double x;
main ()
{
g_init (EGA_640x350);
show (0, 70, -1, 8);
for (x = 0; x < 70; ++x)
plot (x, sin (x/100) + x/10, 1 );
}
the resulting display would fill the width of the screen, but the
vertical scaling would remain unacceptable.
To improve the vertical resolution, one must resort to
anisotropic scaling using the scale () function. Where the show ()
function forced the scaling to be equal in both directions,
scale () will not. Thus,
#include <stdio.h>
#include <math.h>
#include "graph.h"
double x;
main ()
{
g_init (EGA_640x350);
scale (0, 70, -1, 8);
for (x = 0; x < 70; ++x)
plot (x, sin (x/100) + x/10, 1 );
}
will display the data over the entire screen. This is rather
nice, but there is no room for labeling the drawing. We can see
the relative variations the plot, but we have no indication as to
what units are being used and what the magnitude is. To
adequately annotate the plot, we would like to put labels outside
the plotting area so as to leave a clear view of the data.
Defining Viewports
A viewport is a subarea of the plotting area. The borders of
the viewport are called the soft clip limits, and the subarea is
called the soft clip area. The word clip implies that any line
which is draw to a point outside this border will be cut off at
the border (clipped). They are called soft limits because they
can be overridden. To better understand this concept, imagine a
piece of paper with a rectangle drawn on it. We can draw within
the rectangle at any time. We can only draw outside the
rectangle when permission is granted. Permission can be granted
by the clip_off () function, and permission can be denied with
the clip_on () function. The edges of the paper represent the
hard clip limits. These can not be overridden. We can also
change the size of the soft clip limits using the clip ()
function. The clip function units are in UDU's.
For a given hardclip limit on the CRT, the GDU's are fixed and
always predictable. It is for this reason that they are used by
the locate () function. One GDU is defined as "One percent of
the length of the shorter side of the plotting area." GDU's are
always isotropic: one GDU in the x-direction is the same size as
one GDU in the y-direction. However, because of the rectangular
pixels on most PC graphics screens, the number of pixels/GDU
will not be the same in the x-directions as it is in the
y-direction.
At this point, we will define a viewport for our example program.
At the same time, we will introduce the frame () function. The
frame function is used to draw a border around the soft clip
boundary. When g_init () is first called, the hard clip and soft
clip borders are identical. Hence, calling frame () before a
viewport is defined will result in a frame about the hard clip
border.
#include <stdio.h>
#include <math.h>
#include "graph.h"
double x;
main ()
{
g_init (EGA_640x350);
locate (10, 120, 10, 90);
frame ();
scale (0, 70, -1, 8);
for (x = 0; x < 70; ++x) plot (x, sin (x/100) + x/10, 1 );
}
For this example, we are using a 220 mm x 160 mm screen, so there
are 138 GDU's in the x-direction, and 100 GDU's in the
y-direction. Working backwards, we find that the soft clip limit
is about 16 mm in from the screen edges on the top, and left
edge. It is about 29 mm in from the right edge of the screen.
If we had wanted a symmetric display, we could have set the right
edge of the viewport at 128 GDU's.
Labeling the Plot
With the definition of a viewport, we now have a border in which
to label the graph. Typically, the title is centered at the top
of the page, the y-axis label is along the left edge, and the
x-axis label is centered along the bottom.
The labelf () function allows text labels to be place at random
on the screen. This function is distinct from printf () or any
other built-in text generation program. All of the MS-DOS text
programs use raster scan fonts which must be placed in rows and
columns as ordinary ascii text output. Furthermore, the text is
all aligned one-way. It is not possible to rotate the text
without using a rotated font.
Labels are positioned by moving to the desired starting location
with the move () function or plot () function. The lower left
corner of the label will be at the point to which you moved.
Thus, to label the graph,
#include <stdio.h>
#include <math.h>
#include "graph.h"
double x;
main ()
{
g_init (EGA_640x350);
locate (10, 120, 10, 90);
frame ();
move (40, 95);
labelf ("Demonstration Plot");
move (5, 65);
labelf ("D\ne\nv\ni\na\nt\ni\no\nn\n"); /* Deviation */
move (45, 5);
labelf ("Time (seconds)");
scale (0, 70, -1, 8);
for (x = 0; x < 70; ++x) plot (x, sin (x/100) + x/10, 1 );
}
This program now labels the plot with a title (Demonstration
Plot), an x-axis label (Time (seconds) ), and the y-axis label
(Deviation). The y-axis label is broken with '\n' characters so
that the label will be placed vertically. This type of label is
the only type of label possible without rotated fonts on a PC,
but the labelf () function is more versitile than this as will be
shown later.
Creative Labeling
In the previous example, we demonstrated one possible method of
labeling a plot with a vertical label. This resulted in
characters which were "stacked" over each other. We also placed
the title only approximately in the center of the viewport, and
the title was the same size as all of the other characters.
These simplification were used because we were discussing
elementary plotting concepts and additional detail would have
detracted from these basic ideas.
To provide improved labeling, these are three functions which
modify the performance of the labelf () function. The first of
these is csize ( size, a_r, tilt ), and its 3 arguments size,
a_r, and tilt. The first argument, size, regulates the size of
the characters. The initialization default is 5 GDU's. The
size units are always in GDU's. This is the height of the
character cell. The character cell has borders on all sides so
that they may be drawn side-by-side and top-to-bottom without
overlapping. Because all cells are the same size, the amount of
blank space between characters varies with the characters. The
size of a character must always be specified.
The second parameter is the aspect ratio. This is the measure of
the width to the height of a character cell. The characters are
defined on a 9 x 15 grid: hence, the 0.6 default aspect ratio.
At 0.6, the characters are well defined and quite pleasing to the
eye. The aspect ratio may, of course, be increased or decreased
to add emphasis to the labels.
The last parameter is the tilt. This is an angular measure in
the current angular units (radians or degrees) of how far from
vertical the vertical axis of the character cells is tilted.
Positive angles tilt the characters clockwise, and negative
angles tilt the characters counter-clockwise. The effect of
tilting the characters is to italicize them for additional
emphasis.
To use csize (), simply call the function with the desired
parameters. These parameters will remain in effect until csize ()
is called again with different parameters.
Note: the accuracy with which a character is represented and is
visually appealing depends on the screen resolution. This means
that there are pratical limits to how small a character may be
made for a given screen resolution. It is therefore recommended
that you use the highest practical screen resolution consistent
with your other graphics requirements.
The second function which is useful in labeling is lorg () which
selects from 9 label origins. The illustration below shows the
function of lorg ().
3 6 9
+ + +
Test Text Test Text Test Text
5
2 +Test Text Test+Text Test Text + 8
Test Text Test Text
1 + + Test Text + 7
4
The label is "Test Text" and the "+" marks the label origin for
the various origin codes. Thus, if we wanted to center the title
on our graph, we could use
move (65, 95);
lorg (5);
labelf ("Demonstration Plot");
and the label would automatically be centered both vertically and
horizontally about the point (65, 95).
The last of the label enhancement functions is ldir () which
controls the direction labels are drawn. At initialization, the
label direction is at 0 degrees (text is drawn horizontally).
This angle can be set to any angle. Thus, if we say
ldir (90);
the labels will all be drawn vertically upward. If we say
ldir (-90);
the labels will still be drawn vertically, but now the labels
will be drawn vertically downward. There is complete freedom in
choosing the angle at which you want a label to be drawn.
Now, if we add all of the above to the example program, we have
#include <stdio.h>
#include <math.h>
#include "graph.h"
double x;
main ()
{
double x_gdu_max, y_gdu_max;
g_init (EGA_640x350);
/* Determine the screen width and height in GDU's */
x_gdu_max = 100 * max (1, ratio () );
y_gdu_max = 100 * max (1, 1 / ratio () );
locate (10, 120, 10, 90);
frame ();
csize (7,0,0);
/* set the label origin for centered label, top justified */
lorg (6);
move (x_gdu_max / 2, y_gdu_max); /* move to top, middle of crt */
labelf ("Demonstration Plot");
move (50, 65);
lorg (4);
ldir (90);
csize (4,0,0);
labelf ("Deviation");
move (45, 5);
lorg (6);
ldir (0);
labelf ("Time (seconds)");
scale (0, 70, -1, 8);
for (x = 0; x < 70; ++x) plot (x, sin (x/100) + x/10, 1 );
}
we have a plot with an enlarged title and both axes labels well
centered along their respective axes. We could have emboldened
the title slightly be placing the labeling inside a loop which
draws the title successively slightly to the right or left of the
starting point.
for (i = 1; i < 5; ++i)
{
move (65 + i/10, 95);
labelf ("Demonstration Plot");
}
Note that this only emboldens the vertical part of the text, but
the effect is not lost.
We have also introduced a new function: ratio (). ratio () returns
the aspect ratio of the screen. The use of the max () function
simply selects which direction is defined as 100 GDU's. If the
aspect ratio is greater than one, the y-direction will be 100
GDU's, and the x-direction will be 100 * ratio (). If the aspect
ratio is less than one, the x-direction will be 100 GDU's, and
the y-direction will be 100 / ratio (). Thus, we can determine
the shape of the screen without apriori knowledge thereof.
If we add
clip_off ();
move (0, -1);
lorg (8); /* vertically centered, right justified */
labelf ("-1"); /* y-min */
move (0, 8);
labelf ("8"); /* y-max */
move (0, -1);
lorg (6); /* horizontally centered, top justified */
labelf ("0"); /* x-min */
move (70, -1);
labelf ("70"); /* x-max */
we can place labels at the ends of the coordinate axes. The
clip_off () function call is necessary if we are to have visible
labels. This is because the labels are simply a series of
vectors (lines of particular length and direction), and any
portion of a line which lies outside of the soft clip limit will
be cut off when clipping is in effect. The main title and axes
labels were drawn before the locate () function was called, and
these were within the soft and hard clip limits at
initialization (the screen boundaries).
Clipping
Clipping is a hidden function for most graphics applications. It
is completely "under cover" because it functions without explicitly
requesting it. There are two clipping limits: the soft clip
border and the hard clip border. The hard clip limit is
generally an absolute limit determined by the physical size of
the plotting surface (although the hard clip limits can be
changed with the limit () function ). The soft clip border is
user defined. Calling the locate () function automatically
turns on soft clipping at the borders defined by locate ().
The soft clip limits can be set independently of the viewport by
using the clip () function. Calling
clip (20, x_max, 10, y_max);
sets only the soft clip border. The hard clip border is
unchanged. After executing this function, any portion of a line
outside of the x-limits (20 and x_max) or the y-limits (10 and
y_max) will be truncated at the offending edge.
Note that the clip () function uses only UDU's (user defined
units). Thus, it is necessary to call the locate ()
function first to establish a scale for the viewing area. Also,
calling locate () after calling clip () will override the
border set with clip () and set the soft clip limit to the new
border defined by locate ().
We can disable soft clipping with
clip_off ();
and turn it back on with
clip_on ();
and soft clipping will resume at the previous soft clip border.
If we wish to change the soft clip border, we simply use the
clip () function to specify an new boundary. The hard clip
boundary is always on and cannot be disabled.
Drawing Modes
When drawing on the CRT or any erasable device, several drawing
modes are available. You can select "pens" dependent on the
graphics mode selected. In CGA_640x200, there are two colors:
background and foreground. In plotter terminology, you select
pens to determine the color you want to draw. Pen # 0 is always
the background color. For a monochrome drawing, there is only
one other pen: pen # 1. In EGA_640x350, the total number of pens
is 16, or 15 colors plus background. Here, the maximum pen
number is 15.
You can also "undraw" lines. By selecting the negative of the
pen color and drawing over a line, the line is erased. The IBM
BIOS provides two pixel functions: write and XOR. Because of
this limitation, it is not possible to erase only the color
which was drawn. Using the XOR function would do this, but if a
pixel were not illuminated, XOR would make it so. This would
defeat the intent of erasing a line. Therefore, selecting a
negative pen number for erasing a line simply turns off all
pixels on the line, irrespective of color, by writing the
background color to those pixels.
Hewlett-Packard impliments pen # 0 in a slightly different manner
on monochrome CRT's as opposed to color CRT's. On monochrome
CRT's, pen # 0 XOR's pixels. Thus, pen # 0 will write white on a
black pixel, and black on a white pixel.
On a color CRT with a color mapped graphics interface, the
default colors are
Pen Color
0 Black
1 White
2 Red
3 Yellow
4 Green
5 Cyan
6 Blue
7 Magenta
8 Black
9 Olive Green
10 Aqua
11 Royal BLue
12 Maroon
13 Brick Red
14 Orange
15 Brown
This is not the same color set used by the PC color map. On
Hewlett-Packard computers with color mapped displays, it is
possible to change the assigned pen colors. This is possible
only on IBM PC's with EGA compatible video interfaces (which
contain writable color palettes. Also, the Hewlett-Packard
graphics interface allows pixels to be selectively erased.
Thus, a negative pen value will erase only the color values for
that pen. If you change pens before erasing a line, it is
possible to not erase the line but to merely change its color.
For this implimentation, any negative pen value will erase a line
of any color.
Line Types
In order to distinguish between different sets of data drawn in
a single graph, it helps to pattern the lines. To do that, the
function line_type () is used to select from 10 line patterns.
line_type () takes two parameters. The first parameter selects
the pattern, and the second selects the repetition length. The
patterns will be described here. To see the patterns, run
linedemo.exe .
line type description
1 solid
2 dot at endpoint of line
3 lightly dotted
4 headily dotted
5 broken (dashed)
6 broken (long dash) with dot
7 broken (long dash) with short dash
8 broken (long dash) with double dot
9 solid with short tick (1 GDU total length)
10 solid with long tick (2 GDU's total length)
Line types 9 and 10 are implimented slightly differently than in
Hewlett-Packard workstation BASIC. Hewlett-Packard places the
ticks at the endpoint of the line segment. Here, the ticks are
repeated along the length of the line at the repeat rate of the
line. The ticks are drawn either vertically or horizontally.
The orientation depends on the angle of the line. Lines closer
to vertical will have horizontal ticks, and line closer to
horizontal will have vertical ticks. When these lines are drawn
on the screen, however, the apparent angle at which the change
from hoizontal to vertical ticks occurs will not be at 45
degrees as one would expect. This is due to the rectangular
pixels of the PC graphics screen. An extensive discussion of
this is presented under the discription of the function
line_type ().
The second parameter to line_type () is the repetition length.
At initialization, this is 5 GDU's. This can be changed at any
time to any length. It is up to the user to ensure that the
pattern is not so compressed that the detail of the pattern is
lost, or so long that continuity is lost. Unlike the HP BASIC
implimentation, the line repetition need not be integer multiples
of 5 GDU's.
For all line types, the computer keep a record of where it is in
the pattern. Thus, the pattern continues from one line segment
to another. The line can change directions and the pattern will
still be continuous. To start over (as you may want to do if
you are drawing disconnected lines of the same type, simply call
the line_type () function again with the same parameters and the
pattern will start over.
Relative and Incremental Plotting
Up to now, we have discussed only absolute plotting: That is, we
draw and move to specific coordinates. Relative plotting allows
drawing relative to some relocatable origin, and incremental
plotting allows one to draw relative to the last location. For
example,
move (50,50);
rdraw (10,10);
rdraw (10,-10);
rdraw (0,0);
rmove (0,-10);
draws a triangle with verticies at (50,50), (60,60), and (60,40).
We moved to a point (50,50) and then draw relative to that point.
Any absolute motion function ( i.e., move, draw, or plot) can be
used to set this origin. In this example, we have used the rdraw ()
function. We could also have used the rplot () function if we
had required pen control. The last command simply moves the pen
position to (50,40).
The current relative origin is the last location resulting from
calling any of the following commands:
axes () draw () frame () g_init ()
grid () idraw () imove () iplot ()
labelf () move () draw () plot ()
Note that the relative origin is unchanged by any relative motion
functions.
The incremental motion functions (imove, idraw, and iplot) also
change the relative origin. These also move the relative origin
to the specified point. To plot the same triangle using
incremental functions,
move (50,50);
idraw (10,10);
idraw (0,-20);
idraw (-10,10);
imove (0,-10);
Here, the reference position changes to the last location.
idraw (10,10) draws to (60,60), but the reference position now
becomes (60,60). Thus, to get to the point (60,40), we must
move down by 20 units: hence idraw (0,-20). We are now at
(60,40). To get back to (50,50), we move up to and to the left
10, or idraw (-10,10). We used an imove () to move to (50,40).
It looks exactly like the rmove () command from the previous
example because the last drawing command moved us back to our
starting point. If we were not at our starting point, the
commands would not look the same. Again, we could have used
iplot () if we had required control of the pen state (up or
down).
Rotation and Translation of Drawings
In many types of drawings, a single feature or structure is
replicated several times at different locations in the drawing.
We have seen how relative and incremental motion commands can be
used to plot the same figure at any location. We can impart
rotation to lines drawn with these functions by using the pivot ()
and pdir () functions. Each of these functions take a single
argument which is the angle of rotation in the current angular
units (degrees or radians). The function of these two functions
is greatly different, however.
The pdir () function specifies a relative plotting angle. If we
write
move (10,10);
pdir (0);
iplot (1,0);
pdir (-90);
iplot (1,0);
the first line is drawn horizontally, and the second line is
drawn vertically down. This is because we have introduced a
relative rotation of -90 degrees.
We now introduced another element of confusion: logical pen
position and physical pen position. If we assume initialization
values for pivot () and pdir (), the first iplot () moves the
logical and physical pen position to (11,10), and the second
iplot () move the logical and physical pen position to (11,9).
So far, logical and physical pen position move in lock-step.
The following code fragment illustrates the use of the pivot ()
function:
move (10,10);
pivot (90);
iplot (1,0);
We moved to (10,10) and now, instead of changing the relative
plotting direction, we will pivot everything about this point.
Thus, the iplot () function draw a line to (10,11), but it draws
a line vertically up as if we drew to (11,10). Now, the logical
pen position is at (11,10), but the physical pen position is at
(10,11). In effect, we have rotated the coordinate axes 90
degrees about the point (10,10). We have assumed isotropic
scaling in this discussion. If we have anisotropic scaling
(i.e., we used scale () instead of show () ), the apparent line
length would stretch or shrink according to the scales of the x-
and y-axes.
Because pivot works in a logical coordinate system, if we move to
a new location (such as (5,5) ), pivot () will have the effect of
pivoting about those points; it will not pivot about the physical
location of (5,5).
Although the iplot () function was used in this example, pivot
will affect the direction of all lines drawn except labels,
grids, and axes.
At initialization, the pivot point is (0,0) and the pivot angle
is zero.
Miscellaneous Utilities
A graphics dumping utility is also available. It is called
dgraph () and can be used to dump entire screens or partial
screen. It presently is configured for the EPSON FX-80 and 100
type of printers. Unlike the MS-DOS program GRAPHICS.COM or
GRAPHICS.EXE, this program dumps all graphics at the same
orientation to the page. It is somewhat slower than the MS-DOS
version principly because of the way Microsoft C executes calls
to the BIOS.